package cn.hg.solon.youcan.job.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.text.CharSequenceUtil;
import org.dromara.hutool.core.text.StrValidator;
import org.noear.solon.Solon;

import cn.hg.solon.youcan.job.entity.Job;


/**
 * 任务执行工具
 *
 * @author ruoyi
 */
public class JobInvokeUtil {
    /**
     * 获取bean名称
     * 
     * @param invokeTarget
     *            目标字符串
     * @return bean名称
     */
    public static String getBeanName(String invokeTarget) {
        String beanName = CharSequenceUtil.subBefore(invokeTarget, "(", false);
        return CharSequenceUtil.subBefore(beanName, ".", true);
    }

    /**
     * 获取bean方法
     * 
     * @param invokeTarget
     *            目标字符串
     * @return method方法
     */
    public static String getMethodName(String invokeTarget) {
        String methodName = CharSequenceUtil.subBefore(invokeTarget, "(", false);
        return CharSequenceUtil.subAfter(methodName, ".", true);
    }

    /**
     * 获取method方法参数相关列表
     * 
     * @param invokeTarget
     *            目标字符串
     * @return method方法相关参数列表
     */
    public static List<Object[]> getMethodParams(String invokeTarget) {
        String methodStr = CharSequenceUtil.subBetween(invokeTarget, "(", ")");
        if (StrValidator.isEmpty(methodStr)) {
            return null;
        }
        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
        List<Object[]> classs = new LinkedList<>();
        for (int i = 0; i < methodParams.length; i++) {
            String str = CharSequenceUtil.trimToEmpty(methodParams[i]);
            // String字符串类型，以'或"开头
            if (CharSequenceUtil.startWithAny(str, "'", "\"")) {
                classs.add(new Object[] {CharSequenceUtil.sub(str, 1, str.length() - 1), String.class});
            }
            // boolean布尔类型，等于true或者false
            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
                classs.add(new Object[] {Boolean.valueOf(str), Boolean.class});
            }
            // long长整形，以L结尾
            else if (CharSequenceUtil.endWith(str, "L")) {
                classs.add(new Object[] {Long.valueOf(CharSequenceUtil.sub(str, 0, str.length() - 1)), Long.class});
            }
            // double浮点类型，以D结尾
            else if (CharSequenceUtil.endWith(str, "D")) {
                classs.add(new Object[] {Double.valueOf(CharSequenceUtil.sub(str, 0, str.length() - 1)), Double.class});
            }
            // 其他类型归类为整形
            else {
                classs.add(new Object[] {Integer.valueOf(str), Integer.class});
            }
        }
        return classs;
    }

    /**
     * 获取参数类型
     * 
     * @param methodParams
     *            参数相关列表
     * @return 参数类型列表
     */
    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
        Class<?>[] classs = new Class<?>[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            classs[index] = (Class<?>)os[1];
            index++;
        }
        return classs;
    }

    /**
     * 获取参数值
     * 
     * @param methodParams
     *            参数相关列表
     * @return 参数值列表
     */
    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
        Object[] classs = new Object[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            classs[index] = os[0];
            index++;
        }
        return classs;
    }

    /**
     * 调用任务方法
     *
     * @param bean
     *            目标对象
     * @param methodName
     *            方法名称
     * @param methodParams
     *            方法参数
     * @return 返回对象
     */
    private static Object invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
        throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
        InvocationTargetException {
        if (CollUtil.isNotEmpty(methodParams) && methodParams.size() > 0) {
            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
            return method.invoke(bean, getMethodParamsValue(methodParams));
        }
        Method method = bean.getClass().getMethod(methodName);

        return method.invoke(bean);
    }

    /**
     * 执行方法
     *
     * @param sysJob
     *            系统任务
     */
    public static Object invokeMethod(Job sysJob) throws Throwable {
        String invokeTarget = sysJob.getTarget();
        String beanName = getBeanName(invokeTarget);
        String methodName = getMethodName(invokeTarget);
        List<Object[]> methodParams = getMethodParams(invokeTarget);

        if (!isValidClassName(beanName)) {
            Object bean = Solon.context().getBean(beanName);
            return invokeMethod(bean, methodName, methodParams);
        }
        Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();

        return invokeMethod(bean, methodName, methodParams);
    }

    /**
     * 校验是否为为class包名
     * 
     * @param invokeTarget
     *            名称
     * @return true是 false否
     */
    public static boolean isValidClassName(String invokeTarget) {
        return CharSequenceUtil.count(invokeTarget, ".") > 1;
    }
}
